package main

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"io"
	"log/slog"
	"os"
	"path/filepath"
	"time"

	"github.com/joho/godotenv"
)

// LicenseInfo 必须与验证器中的结构完全一致
type LicenseInfo struct {
	CustomerID  string    `json:"customer_id"`
	ProductID   string    `json:"product_id"`
	ExpiryDate  time.Time `json:"expiry_date"`
	MaxUsers    int       `json:"max_users"`
	LicenseType string    `json:"license_type"`
}

// SignedLicense 包含许可证数据及其RSA-PSS签名
type SignedLicense struct {
	Data      string `json:"data"`      // LicenseInfo的Base64编码JSON
	Signature string `json:"signature"` // RSA-PSS签名(Base64编码)
}

func main() {
	err := godotenv.Load()
	if err != nil {
		slog.Error("Failed to load env", "error", err)
		return
	}

	privateKeyPath := os.Getenv("PRIVATE_KEY_PATH")
	outputLicenseFile := fmt.Sprintf("%s/%s" ,os.Getenv("OUT_LICENSE_PATH"),"license.lic")
	expiredDate, err := time.Parse("2006-01-02", os.Getenv("EXPIRY_DATE"))
	if err != nil {
		slog.Error("Failed parse expired date", "error", err)
	}
	// 1. 定义许可证信息
	licenseInfo := LicenseInfo{
		CustomerID: os.Getenv("CUSTOMER_ID"),
		ProductID:  os.Getenv("PRODUCT_ID"),
		ExpiryDate: expiredDate,
	}

	// 2. 生成签名许可证文件
	err = generateSignedLicense(licenseInfo, privateKeyPath, outputLicenseFile)
	copyFile(os.Getenv("PUBLIC_KEY_PATH"),fmt.Sprintf("%s/%s" ,os.Getenv("OUT_LICENSE_PATH"),"license_public_key.pem"),0400)
	if err != nil {
		slog.Error("Failed to generate the license signature", "error", err)
	}
	slog.Info("The signed license has been generated successfully", "outputLicenseFile", outputLicenseFile)
}

// generateSignedLicense 创建并签名许可证
func generateSignedLicense(info LicenseInfo, privateKeyPath, outputPath string) error {
	// 读取私钥文件
	privateKeyData, err := os.ReadFile(privateKeyPath)
	if err != nil {
		slog.Error("Failed to read the private key file", "error", err)
		return errors.New("failed to read the private key file")
	}
	block, _ := pem.Decode(privateKeyData)
	if block == nil {
		slog.Error("Unable to decode the PEM-formatted private key")
		return fmt.Errorf("unable to decode the PEM-formatted private key")
	}
	// 首先尝试将其作为 PKCS#1 格式解析
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		slog.Error("Failed parse PKCS1 private key", "error", err)
		return err
	}

	// 将许可证信息序列化为JSON并进行Base64编码
	infoJSON, err := json.Marshal(info)
	if err != nil {
		return fmt.Errorf("failed to marshal license info: %w", err)
	}

	encodedData := base64.StdEncoding.EncodeToString(infoJSON)

	// 使用RSA-PSSwithSHA256对编码后的数据进行签名
	hasher := sha256.New()
	hasher.Write([]byte(encodedData))
	hashed := hasher.Sum(nil)

	// 使用PSS模式进行签名，安全性更高
	signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA256, hashed, &rsa.PSSOptions{
		SaltLength: rsa.PSSSaltLengthAuto, // 盐长度自动计算
		Hash:       crypto.SHA256,
	})
	if err != nil {
		return fmt.Errorf("failed to PASS sign: %w", err)
	}
	encodedSignature := base64.StdEncoding.EncodeToString(signature)

	// 组装签名许可证
	signedLicense := SignedLicense{
		Data:      encodedData,
		Signature: encodedSignature,
	}

	// 将签名许可证写入文件
	licenseJSON, err := json.MarshalIndent(signedLicense, "", "    ")
	if err != nil {
		return fmt.Errorf("failed to serialize the signed license: %w", err)
	}
	return os.WriteFile(outputPath, licenseJSON, 0o644)
}

func CopyDir(src, dst string) error {
    // 首先创建目标根目录
    srcInfo, err := os.Stat(src)
    if err != nil {
        return err
    }
    if err := os.MkdirAll(dst, srcInfo.Mode()); err != nil {
        return err
    }

    entries, err := os.ReadDir(src)
    if err != nil {
        return err
    }

    for _, entry := range entries {
        srcPath := filepath.Join(src, entry.Name())
        dstPath := filepath.Join(dst, entry.Name())

        if entry.IsDir() {
            // 如果是子目录，递归调用
            if err := CopyDir(srcPath, dstPath); err != nil {
                return err
            }
        } else {
            // 如果是文件，复制文件
            info, err := entry.Info()
            if err != nil {
                return err
            }
            if err := copyFile(srcPath, dstPath, info.Mode()); err != nil {
                return err
            }
        }
    }
    return nil
}

func copyFile(src, dst string, mode os.FileMode) error {
    srcFile, err := os.Open(src)
    if err != nil {
        return err
    }
    defer srcFile.Close()

    dstFile, err := os.Create(dst)
    if err != nil {
        return err
    }
    defer dstFile.Close()

    if _, err := io.Copy(dstFile, srcFile); err != nil {
        return err
    }

    // 可选：设置文件权限
    return os.Chmod(dst, mode)
}